/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*                                                                    *
*        ***************************************************         *
*        *©2021-2031 LINUO Corporation All rights reserved *         *
*        ***************************************************         *
*                                                                    *
* FileName    : njte.cpp                                             *
*                                                                    *
* Author      : linus                                                *
*                                                                    *
* Email       : luoyaojun@sina.com                                   *
*                                                                    *
* Date        : 2024-3-25                                            *
*                                                                    *
* Description :                                                      *
*                                                                    *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "arm_neon.h"

#include <stdio.h>
#include "ht_mpp.h"
#include "demo_rtsp.h"
#include <sys/time.h>
#include "AlgoChannel.h"
#include "rk_mpi_rgn.h"
#include "rk_mpi_cal.h"
#include <sys/prctl.h>
#include <opencv2/opencv.hpp>

#define AVS_OUT_WIDTH	7680
#define AVS_OUT_HEIGHT	1080

static bool m_exit = false;
static pthread_t m_phOSDThread;
static bool m_write = true;
static long long lastCapTime = 0;
static int capCount = 0;

HT_S32 ht_venc_get_frame_cb(void *user, void *data, HT_S32 len, HT_U64 pts)
{
	printf("-----\n");
	rtsp_service_write_ch((struct rtsp_config *)user, 0, (HT_U8 *)data, len, pts);
	return 0;
}
HT_S32 ht_venc_get_frame_cb1(void *user, void *data, HT_S32 len, HT_U64 pts)
{

	if(m_write == true && pts > lastCapTime + 500 * 1000)
	{
        std::string filename = "/mnt/" + std::to_string(pts) + ".jpg";
        std::ofstream outFile(filename, std::ios::binary);
        outFile.write((char *)data, len);
        outFile.close();
        lastCapTime = pts;
        if(capCount++ >= 5)
        {    
            m_write = false;
        }
	}
	return 0;
}
HT_S32 ht_venc_get_frame_cb2(void *user, void *data, HT_S32 len, HT_U64 pts)
{
	rtsp_service_write_ch((struct rtsp_config *)user, 2, (HT_U8 *)data, len, pts);
	return 0;
}
HT_S32 ht_venc_get_frame_cb3(void *user, void *data, HT_S32 len, HT_U64 pts)
{
	rtsp_service_write_ch((struct rtsp_config *)user, 3, (HT_U8 *)data, len, pts);
	return 0;
}
HT_S32 ht_venc_get_frame_cb4(void *user, void *data, HT_S32 len, HT_U64 pts)
{
	rtsp_service_write_ch((struct rtsp_config *)user, 4, (HT_U8 *)data, len, pts);
	return 0;
}
HT_S32 ht_venc_get_frame_cb5(void *user, void *data, HT_S32 len, HT_U64 pts)
{
	rtsp_service_write_ch((struct rtsp_config *)user, 5, (HT_U8 *)data, len, pts);
	return 0;
}

HT_S32 ht_venc_get_frame_cb6(void *user, void *data, HT_S32 len, HT_U64 pts)
{
	rtsp_service_write_ch((struct rtsp_config *)user, 6, (HT_U8 *)data, len, pts);
	return 0;
}

HT_S32 vpss_chn_get_frame_cb(HT_S32 vpss_grp, HT_S32 vpss_chn, HT_VOID *user, HT_FRAME frame_out)
{
	printf("---------------->>> vpss_grp = %d vpss_chn = %d %d\n", vpss_grp, vpss_chn, *(int *)user);

	return 0;
}

static int vi_avs_venc_rtsp_imx464(void)
{
	struct rtsp_config *pconfig;
	struct ht_vi_config info = {0};
	struct ht_isp_config isp = {0};
	int i = 0;
	
	pconfig = rtsp_service_init_h264(554, AVS_OUT_WIDTH, AVS_OUT_HEIGHT, 30);

	rtsp_service_request_chn(pconfig, 0);
	rtsp_service_request_chn(pconfig, 1);
	rtsp_service_request_chn(pconfig, 2);
	rtsp_service_request_chn(pconfig, 3);
	rtsp_service_request_chn(pconfig, 4);
	rtsp_service_request_chn(pconfig, 5);
	rtsp_service_request_chn(pconfig, 6);

	isp.rconfig.camera_count = 6;
	isp.rconfig.mode = HT_ISP_SYNC;

	ht_isp_init(&isp);

	ht_avs_init();
	
	for (i = 0; i < 6; i++)
	{
		ht_vi_dev_init(i);
		memset(&info, 0, sizeof(struct ht_vi_config));

		info.res.width = 2560;
		info.res.height = 1520;
//		ht_venc_init(i+1, 2560, 1520, HT_VIDEO_ID_H264);
		
	  	ht_vi_chn_init(i, 0, &info);

//		ht_sys_bind(HT_ID_VI, i, 0, HT_ID_VENC, 0, i+1);
	}
	
	ht_sys_bind(HT_ID_VI, 0, 0, HT_ID_AVS, 0, 0);
	ht_sys_bind(HT_ID_VI, 1, 0, HT_ID_AVS, 0, 1);
	ht_sys_bind(HT_ID_VI, 2, 0, HT_ID_AVS, 0, 2);
	ht_sys_bind(HT_ID_VI, 3, 0, HT_ID_AVS, 0, 3);
	ht_sys_bind(HT_ID_VI, 4, 0, HT_ID_AVS, 0, 4);
	ht_sys_bind(HT_ID_VI, 5, 0, HT_ID_AVS, 0, 5);
	//	vppss create
	ht_vpss_group_init(0, HT_FMT_YUV420SP);
	ht_vpss_chn_init(0, 0, AVS_OUT_WIDTH, AVS_OUT_HEIGHT, HT_FMT_YUV420SP, 5);

	//	avs bind vpss
	ht_sys_bind(HT_ID_AVS, 0, 0, HT_ID_VPSS, 0, 0);

//	ht_vpss_chn_get_frame(0, 0, vpss_chn_get_frame_cb, NULL);
	//	venc create
	ht_venc_init(0, AVS_OUT_WIDTH, AVS_OUT_HEIGHT, HT_VIDEO_ID_H264);
        ht_venc_init(1, AVS_OUT_WIDTH, AVS_OUT_HEIGHT, HT_VIDEO_ID_JPEG);
	//	vpss bind venc
//	ht_sys_bind(HT_ID_VPSS, 0, 0, HT_ID_VENC, 0, 0);

	ht_venc_get_frame(0, ht_venc_get_frame_cb, pconfig);
	ht_venc_get_frame(1, ht_venc_get_frame_cb1, pconfig);
//	ht_venc_get_frame(2, ht_venc_get_frame_cb2, pconfig);
//	ht_venc_get_frame(3, ht_venc_get_frame_cb3, pconfig);
//	ht_venc_get_frame(4, ht_venc_get_frame_cb4, pconfig);
//	ht_venc_get_frame(5, ht_venc_get_frame_cb5, pconfig);
//	ht_venc_get_frame(6, ht_venc_get_frame_cb6, pconfig);

	return 0;
}

void onDetectDataCallback(std::vector<DRESULT> results)
{
    int i = 0;

    if(results.size() >= 1)
    {
        capCount = 0;
        m_write = true;
    }
    //count = i;
    return;
}

static int createRegion(int handle,int vpssGrp,int vpssChn,int width,int height)
{
    int ret = 0;
    RGN_ATTR_S stRgnAttr;
    RGN_CHN_ATTR_S stChnAttr;
    MPP_CHN_S stChn;

    memset(&stRgnAttr, 0, sizeof(stRgnAttr));
    memset(&stChnAttr, 0, sizeof(stChnAttr));

    stRgnAttr.enType = OVERLAY_RGN;
    stRgnAttr.unAttr.stOverlay.enPixelFmt = RK_FMT_BGRA8888;
    stRgnAttr.unAttr.stOverlay.stSize.u32Width = width / 4 * 4;
    stRgnAttr.unAttr.stOverlay.stSize.u32Height = height / 4 * 4;
    stRgnAttr.unAttr.stOverlay.u32CanvasNum = 1;
    stRgnAttr.unAttr.stOverlay.u32ClutNum = 0;

    ret = RK_MPI_RGN_Create(handle, &stRgnAttr);
    if (ret != 0){
        printf("RK_MPI_RGN_Create failed! ret: 0x%x.\n", ret);
        return -1;
    }

    stChnAttr.bShow = RK_TRUE;
    stChnAttr.enType = OVERLAY_RGN;
    stChnAttr.unChnAttr.stOverlayChn.stPoint.s32X = 100;
    stChnAttr.unChnAttr.stOverlayChn.stPoint.s32Y = 100;
    stChnAttr.unChnAttr.stOverlayChn.u32BgAlpha = 0;
    stChnAttr.unChnAttr.stOverlayChn.u32FgAlpha = 0;
    stChnAttr.unChnAttr.stOverlayChn.u32Layer = 0;
    stChnAttr.unChnAttr.stOverlayChn.stQpInfo.bEnable = RK_FALSE;

    /*attach the OSD to the VPSS*/
    stChn.enModId = RK_ID_VPSS;
    stChn.s32DevId = vpssGrp;
    stChn.s32ChnId = vpssChn;

    ret = RK_MPI_RGN_AttachToChn(handle, &stChn, &stChnAttr);
    if (ret != 0){
        printf("RK_MPI_RGN_AttachToChn failed! ret: 0x%x.\n", ret);
        return -1;
    }

    return 0;
}

static int destoryRegion(int handle,int vpssGrp,int vpssChn)
{
    int ret = 0;
    MPP_CHN_S stChn;

    stChn.enModId = RK_ID_VPSS;
    stChn.s32DevId = vpssGrp;
    stChn.s32ChnId = vpssChn;

    ret = RK_MPI_RGN_DetachFromChn(handle, &stChn);
    if (ret != 0){
        printf("RK_MPI_RGN_DetachFromChn failed! ret: 0x%x.\n", ret);
        // return -1;
    }

    ret = RK_MPI_RGN_Destroy(handle);
    if (0 != ret){
        printf("RK_MPI_RGN_Destroy failed! ret: 0x%x.\n", ret);
    }

    return 0;
}

static void *refreshOsdCallback(void *param){
    int handle = 0;
    int vpssGrp = 0;
    int vpssChn = 0;
    int width = 780;
    int height = 80;
    char currTime[128] = {0};
    prctl(PR_SET_NAME,"OSD");
    cv::Mat argbSrcImage = cv::Mat::zeros(cv::Size(width, height), CV_8UC4);
//    uint16_t *argbDstImage = (uint16_t *)malloc(width*height*2);
    
    createRegion(handle,vpssGrp,vpssChn,width,height);
    while(!m_exit)
    {
        int ret = 0;

        time_t now = time(nullptr);
        tm *ptime = localtime(&now);
        sprintf(currTime, "%04d-%02d-%02d %02d:%02d:%02d", (ptime->tm_year + 1900),
            ptime->tm_mon + 1, ptime->tm_mday, ptime->tm_hour, ptime->tm_min, ptime->tm_sec);

        memset(argbSrcImage.data, 0, width*height*4);
        cv::putText(argbSrcImage, currTime, cv::Point(0,55), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0xFF,0xFF,0xFF,0xFF), 2);

//        for (int y = 0; y < height; ++y) {
//            for (int x = 0; x < width; ++x) {
//                cv::Vec4i argb8888 = argbSrcImage.at<cv::Vec4i>(y, x);
//    
//                // 提取ARGB8888的各个分量
//                uint8_t a = argb8888[0]; // Alpha
//                uint8_t r = argb8888[1]; // Red
//                uint8_t g = argb8888[2]; // Green
//                uint8_t b = argb8888[3]; // Blue（注意：OpenCV的BGR顺序，但这里假设已经是ARGB）
//    
//                // 将ARGB8888分量转换为ARGB1555格式
//                uint16_t argb1555 = 0;
//                argb1555 |= ((a > 127) ? 0x8000 : 0x0000); // Alpha: 1位
//                argb1555 |= ((r >> 3) & 0x1F) << 10;      // Red: 5位
//                argb1555 |= ((g >> 3) & 0x1F) << 5;       // Green: 5位
//                argb1555 |= (b >> 3) & 0x1F;              // Blue: 5位
//    
//                argbDstImage[y * width + x] = argb1555;
//            }
//        }

        BITMAP_S stOsdBmp;
        memset(&stOsdBmp, 0, sizeof(stOsdBmp));
        stOsdBmp.enPixelFormat = RK_FMT_BGRA8888;
        stOsdBmp.pData = (void*)argbSrcImage.data;
        stOsdBmp.u32Width = width;
        stOsdBmp.u32Height = height;
        
        ret = RK_MPI_RGN_SetBitMap(handle, &stOsdBmp);
        if (0 != ret){
            printf("\033[0;31mtest case <%s>not pass at line:%d err:%x\033[0;39m\n", __FUNCTION__, __LINE__, ret);
        }
        usleep(200*1000);
    }

    destoryRegion(handle,vpssGrp,vpssChn);

    return NULL;
}

static int startOsd()
{
    m_exit = false;
    int iRet = pthread_create(&m_phOSDThread, NULL, refreshOsdCallback, NULL);
    if (iRet != 0){
        printf("create thread err\n");
        return -1;
    }

    return 0;
}

static int stopOsd()
{
    m_exit = true;

    pthread_detach(m_phOSDThread);
    return 0;
}

int main(int argc, char **argv)
{
	unsigned char *pucOSD = (unsigned char *)malloc(1000 * 100 * 4);
	AlgoChannel m_algoChannel;
	ht_sys_init();
	
	vi_avs_venc_rtsp_imx464();

	startOsd();
	m_algoChannel.Init("/root/test.rknn",640,640);
	m_algoChannel.setDetectDataCallback(onDetectDataCallback);
	pause();
	stopOsd();
	m_algoChannel.Destory();
}
